#pragma once
#include "index.hpp"
#include "util.hpp"
#include <algorithm>
#include <jsoncpp/json/json.h>
#include "log.hpp"
namespace ns_searcher
{
  struct InvertedElemPrint
  {
    uint64_t doc_id;
    int weight;
    std::vector<std::string> words;
    InvertedElemPrint():doc_id(0),weight(0){}
  };
  class Searcher
  {
    public:
      Searcher(){}
      ~Searcher(){}

      void InitSearcher(const std::string& input)
      {
        //1. 获取或创建index对象
        index = ns_index::Index::GetInstance();
        LOG(NORMAL,"Get instance success...");
        //2.根据index对象创建索引
        index->BulidIndex(input);
        LOG(NORMAL,"Build index success...");
      }

      void Search(const std::string& query,std::string* json_string)
      {
        //1. 对query进行分词
        std::vector<std::string> words;
        ns_util::JiebaUtil::CutString(query,&words); 
        //2. 根据分词使用index查找
        //ns_index::InvertedList inverted_list_all;
        std::vector<InvertedElemPrint> inverted_list_all;
        std::unordered_map<uint64_t,InvertedElemPrint> tokens_map;
        for(std::string word : words)
        {
          boost::to_lower(word);
          ns_index::InvertedList* inverted_list = index->GetInvertedList(word);
          if(nullptr == inverted_list)
          {
            continue;
          }
          //inverted_list_all.insert(inverted_list_all.end(),inverted_list->begin(),inverted_list->end());
          //将一个倒排拉链中相同id的文件节点整合到一块
          for(const auto& elem : *inverted_list)
          {
            auto& item = tokens_map[elem.doc_id];
            item.doc_id = elem.doc_id;
            item.weight += elem.weight;
            item.words.push_back(elem.word);
          }
          for(const auto& item : tokens_map)
          {
            inverted_list_all.push_back(std::move(item.second));
          }
        }
        //3. 汇总查找结果，根据weight降序排序
        std::sort(inverted_list_all.begin(),inverted_list_all.end(),
            [](const InvertedElemPrint& e1,const InvertedElemPrint& e2)
            {
              return e1.weight>e2.weight;
            });
        //4. 根据查找出来的结果构建jason串
        Json::Value root;
        for(auto& item: inverted_list_all)
        {
          ns_index::DocInfo* doc = index->GetForwardIndex(item.doc_id);
          if(nullptr == doc)
          {
            continue;
          }
          Json::Value elem;
          elem["title"] = doc->title;
          //elem["desc"] = GetDesc(doc->content,item.word);
          elem["desc"] = GetDesc(doc->content,item.words[0]);
          elem["url"] = doc->url;
          //for debug
          elem["id"] = (int)item.doc_id;
          elem["weight"] = item.weight;
          root.append(elem);
        }
        Json::StyledWriter writer;
        *json_string = writer.write(root);
      }
      std::string GetDesc(const std::string& content,const std::string& word)
      {
        //截取包含关键字的部分内容
        const std::size_t prev_step = 30;
        const std::size_t next_step = 120;

        //1.找到首次出现
        auto iter = std::search(content.begin(),content.end(),word.begin(),word.end(),[](int x,int y){
            return (std::tolower(x)==std::tolower(y));
            });
        if(iter == content.end())
        {
          return "None1";//实际上不可能找遍文档没有关键字
        }
        std::size_t pos = std::distance(content.begin(),iter);

        //2.获取start和end
        std::size_t start = 0;
        std::size_t end = content.size()-1;
        if(pos > prev_step + start) start = pos - prev_step;
        if(pos + next_step < end) end = pos + next_step;
        //3.截取子串
        if(start>=end)
        {
          return "None2";
        }
        std::string desc =  content.substr(start,end-start);
        desc += "...";
        return desc;
      }

    private:
      ns_index::Index* index;
  };
}
